package com.icinfo.cloud.provider.punish.common.documentoperate.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.icinfo.cloud.provider.common.constant.Constant;
import com.icinfo.cloud.provider.punish.common.documentoperate.dto.OldJycxDocumentDealDTO;
import com.icinfo.cloud.provider.punish.common.documentoperate.service.IOldDocumentOperateService;
import com.icinfo.cloud.provider.punish.common.documentoperate.service.IStageDocCommonOperateService;
import com.icinfo.cloud.provider.punish.config.model.SysDepartParam;
import com.icinfo.cloud.provider.punish.config.service.ISysDepartParamService;
import com.icinfo.cloud.provider.punish.ucase.casemain.enums.CaseTypeEnum;
import com.icinfo.cloud.provider.punish.ucase.casemain.mapper.CaseDocumentRecordMapper;
import com.icinfo.cloud.provider.punish.ucase.casemain.mapper.CaseMainInfoMapper;
import com.icinfo.cloud.provider.punish.ucase.casemain.model.CaseDocumentRecord;
import com.icinfo.cloud.provider.punish.ucase.casemain.model.CaseMainInfo;
import com.icinfo.framework.mybatis.mapper.entity.Example;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 描述：历史文书处理逻辑
 *
 * @author xiangyuyu
 * @date 2022/2/16 21:07
 */
@Service
@Slf4j
public class OldDocumentOperateServiceImpl implements IOldDocumentOperateService {
    private ThreadPoolExecutor THREAD_POOL = new ThreadPoolExecutor(
            2,
            4,
            30L,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(1000),
            r -> new Thread(r, "old-document-operate-pool-" + r.hashCode()),
            (r, executor) -> r.run());
    @Resource
    private CaseDocumentRecordMapper caseDocumentRecordMapper;

    @Resource
    private CaseMainInfoMapper caseMainInfoMapper;

    @Resource
    private ISysDepartParamService sysDepartParamService;

    @Resource
    private IStageDocCommonOperateService stageDocCommonOperateService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void oldJycxDocumentDeal(OldJycxDocumentDealDTO dto) {
        //获取文书记录集合
        List<CaseDocumentRecord> caseDocumentRecords = getDocumentRecords(dto);
        //根据案件分组
        Map<String, List<CaseDocumentRecord>> caseDocumentGroupMap = caseDocumentRecords.stream().collect(Collectors.groupingBy(CaseDocumentRecord::getCaseId));
        //获取案件集合
        List<CaseMainInfo> caseMainInfos = getJycxCaseByDocumentRecords(caseDocumentRecords);
        //获取部门标准名称map key-> org+dept value->orgStandardName
        Map<String, SysDepartParam> sysDepartParamMap = getStandardNameMap(caseMainInfos);
        if (CollUtil.isEmpty(caseMainInfos)) {
            return;
        }
        CountDownLatch ct = new CountDownLatch(caseMainInfos.size());
        //循环案件
        for (CaseMainInfo caseInfo : caseMainInfos) {
            //线程池执行简易程序历史文书处理
            THREAD_POOL.execute(() -> {
                try {
                    dealJycxOldDocument(caseInfo, caseDocumentGroupMap, sysDepartParamMap);
                } finally {
                    ct.countDown();
                }
            });
        }
        try {
            ct.await();
        } catch (InterruptedException e) {
            throw new RuntimeException("异常中断");
        }
    }

    /**
     * 处理历史文书
     *
     * @param caseInfo             案件信息
     * @param caseDocumentGroupMap 案件文书分组
     * @param standardNameMap      部门标准名称map
     */
    private void dealJycxOldDocument(CaseMainInfo caseInfo,
                                     Map<String, List<CaseDocumentRecord>> caseDocumentGroupMap,
                                     Map<String, SysDepartParam> standardNameMap) {
        List<CaseDocumentRecord> documentRecords = caseDocumentGroupMap.get(caseInfo.getId());
        SysDepartParam sysDepartParam = standardNameMap.get(assemblyOrgAndDeptKey(caseInfo.getCaseOrgCode(), caseInfo.getCaseDeptCode()));
        List<String> needRebuildDocumentIds = new LinkedList<>();
        for (CaseDocumentRecord documentRecord : documentRecords) {
            JSONObject documentParams = JSON.parseObject(documentRecord.getDocumentContent());
//            if (StrUtil.isNotEmpty(documentParams.getString("orgStandardName"))) {
//                //若数据已经存在则不需要处理
//                continue;
//            }
            documentParams.put("orgStandardName", sysDepartParam.getOrgStandardName());
            CaseDocumentRecord updateRecord = new CaseDocumentRecord();
            updateRecord.setId(documentRecord.getId());
            updateRecord.setDocumentContent(JSON.toJSONString(documentParams));
            //修改数据
            caseDocumentRecordMapper.updateByPrimaryKeySelective(updateRecord);
            //增加待重新构建文书id
            needRebuildDocumentIds.add(documentRecord.getId());
        }
        if (CollUtil.isEmpty(needRebuildDocumentIds)) {
            return;
        }
        //重新生成文书
        stageDocCommonOperateService.rebuildPdf(buildRebuildPdfParams("JYCX", sysDepartParam, needRebuildDocumentIds));
    }

    /**
     * 构建重新生成文书参数
     *
     * @param documentType           文书类型 参考stageDocCommonOperateService.rebuildPdf参数
     * @param sysDepartParam
     * @param needRebuildDocumentIds 待重新生成文书id
     * @return
     */
    private static Map<String, Object> buildRebuildPdfParams(String documentType, SysDepartParam sysDepartParam, List<String> needRebuildDocumentIds) {
        Map<String, Object> paramJson = new HashMap<>();
        paramJson.put("documentType", documentType);
        List<Map<String, String>> documentInfo = new LinkedList<>(needRebuildDocumentIds.stream()
                .map(id -> new HashMap<String, String>() {{
                    put("documentId", id);
                    put("uniscid", sysDepartParam.getUnicode());
                }}).collect(Collectors.toList()));
        paramJson.put("documentInfo", documentInfo);
        return paramJson;
    }

    /**
     * 获取文书记录集合
     *
     * @param dto
     * @return
     */
    private List<CaseDocumentRecord> getDocumentRecords(OldJycxDocumentDealDTO dto) {
        Example recordExample = new Example(CaseDocumentRecord.class);
        Example.Criteria criteria = recordExample.createCriteria();
        criteria.andIsNotNull("documentCreateTime");
        criteria.andIsNotNull("caseId");
        if (StrUtil.isNotEmpty(dto.getStartTime())) {
            criteria.andGreaterThanOrEqualTo("documentCreateTime", DateUtil.parse(dto.getStartTime()));
        }
        if (StrUtil.isNotEmpty(dto.getEndTime())) {
            criteria.andLessThanOrEqualTo("documentCreateTime", DateUtil.parse(dto.getEndTime()));
        }
        if (CollUtil.isNotEmpty(dto.getDocumentIds())) {
            criteria.andIn("id", dto.getDocumentIds());
        }
        if (CollUtil.isNotEmpty(dto.getDocumentCatalogCodes())) {
            criteria.andIn("documentCatalogCode", dto.getDocumentCatalogCodes());
        }
        //获取文书数据
        List<CaseDocumentRecord> caseDocumentRecords = caseDocumentRecordMapper.selectByExample(recordExample);
        return caseDocumentRecords;
    }

    /**
     * 根据文书集合获取案件信息集合
     *
     * @param caseDocumentRecords
     * @return
     */
    private List<CaseMainInfo> getJycxCaseByDocumentRecords(List<CaseDocumentRecord> caseDocumentRecords) {
        if (CollUtil.isEmpty(caseDocumentRecords)) {
            return Collections.emptyList();
        }
        //获取案件id集合
        List<String> caseIds = caseDocumentRecords.stream().map(CaseDocumentRecord::getCaseId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        Example caseExample = new Example(CaseMainInfo.class);
        caseExample.createCriteria().andIn("id", caseIds).andEqualTo("caseType", CaseTypeEnum.SIMPLE_PROCEDURE.getCode());
        //筛选简易程序
        return caseMainInfoMapper.selectByExample(caseExample);
    }

    /**
     * 获取部门名称 key-> org+dept value->orgStandardName
     *
     * @param caseMainInfos
     * @return 部门名称 key-> org+dept value->SysDepartParam
     */
    private Map<String, SysDepartParam> getStandardNameMap(List<CaseMainInfo> caseMainInfos) {
        if (CollUtil.isEmpty(caseMainInfos)) {
            return Collections.emptyMap();
        }
        //根据部门分组的集合
        Map<String, List<CaseMainInfo>> orgGroupMap = caseMainInfos.stream()
                .collect(Collectors.groupingBy(caseInfo -> assemblyOrgAndDeptKey(caseInfo.getCaseOrgCode(), caseInfo.getCaseDeptCode())));

        //获取部门名称 key-> org+dept value->orgStandardName
        Map<String, SysDepartParam> standardNameMap = new HashMap<>();
        orgGroupMap.forEach((k, caseList) -> {
            CaseMainInfo caseMainInfo = caseList.get(Constant.INTEGER_0);
            SysDepartParam sysDepartParam = sysDepartParamService.getSysDepartParamByOrgCodeAndDeptCode(caseMainInfo.getCaseOrgCode(), caseMainInfo.getCaseDeptCode());
            if (Objects.isNull(sysDepartParam)) {
                return;
            }
            //部门名称
            standardNameMap.put(k, sysDepartParam);
        });
        return standardNameMap;
    }

    /**
     * 组装org和dept的key
     *
     * @param orgCode
     * @param deptCode
     * @return
     */
    private String assemblyOrgAndDeptKey(String orgCode, String deptCode) {
        return Optional.ofNullable(orgCode).orElse("") + "|" + Optional.ofNullable(deptCode).orElse("");
    }
}
